package ch.ethz.fcl.metrobuzz.data.transit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Node;
import ch.ethz.fcl.metrobuzz.data.singapore.SGTransitType;
import ch.ethz.fcl.metrobuzz.data.singapore.SGTransitType.TransitType;
import ch.ethz.fcl.metrobuzz.data.transit.bus.CalibratedBusSchedule;
import ch.ethz.fcl.metrobuzz.data.transit.bus.RawBusSchedule;
import ch.ethz.fcl.metrobuzz.render.accessbility.bus_schedule.BusScheduleVisualizer;

public class Stop extends Node {
	private Edge edge;
	// list of passing routes in the schedule
	private List<TransitRoute> passingRoutes;

	// frequency of the buses passing through this stop over a day
	private Map<TransitRoute, Integer[]> passingRouteFrequency;
	// list of stops close to this stop
	private Map<Stop, Float> closeStopMap;
	// correspondin node name for train stations
	private String correspondingNodeId = null;

	public Stop(String id, Edge edge, float x, float y) {
		super(id, x, y);
		this.edge = edge;

		passingRoutes = new ArrayList<TransitRoute>();

		passingRouteFrequency = new HashMap<TransitRoute, Integer[]>();
		closeStopMap = new HashMap<Stop, Float>();
	}

	public void addPassingRoute(TransitRoute route) {
		if (!passingRoutes.contains(route)) {
			passingRoutes.add(route);
			Integer[] frequency = new Integer[MBData.ONE_DAY_TIME];
			for (int i = 0; i < MBData.ONE_DAY_TIME; i++)
				frequency[i] = 0;
			passingRouteFrequency.put(route, frequency);
		}
	}

	public TransitRoute getPassingRoute(String routeName) {
		// System.out.println("route name " + routeName);
		for (TransitRoute route : passingRoutes)
			if (route.getId().equals(routeName))
				return route;
		return null;
	}

	public List<TransitRoute> getPassingRoutes() {
		return passingRoutes;
	}

	public void vehiclePass(TransitRoute route, int time) {
		if (time < 0 || time >= MBData.ONE_DAY_TIME) {
			// System.out.println("time not valid " + time);
			return;
		}

		Integer[] frequency = passingRouteFrequency.get(route);
		if (frequency == null) {
			System.out.println("frequency not available " + route.getId());
			return;
		}

		frequency[time]++;

		passingRouteFrequency.remove(route);
		passingRouteFrequency.put(route, frequency);
	}

	// get the number of the route passing by this stop during a period of time
	public int getRouteFrequency(TransitRoute route, int time, int period) {
		if (time < 0 || time >= MBData.ONE_DAY_TIME) {
			System.out.println("time not valid " + time);
			return -1;
		}
		Integer[] frequency = passingRouteFrequency.get(route);
		if (frequency == null) {
			System.out.println("frequency not available");
			return -1;
		}

		int totalFreq = 0;
		for (int i = 0; i < period; i++)
			if (time + i < MBData.ONE_DAY_TIME)
				totalFreq += frequency[time + i];

		return totalFreq;
	}

	public void addCloseStop(Stop stop, float time) {
		if (closeStopMap.get(stop) == null)
			closeStopMap.put(stop, time);
	}

	public Map<Stop, Float> getCloseStopsMap() {
		return closeStopMap;
	}

	public void init(MBData data) {
		if (SGTransitType.getTransitType(id) == TransitType.MRT)
			for (Node node : data.getScene().getNodes()) {
				String[] names = node.getId().split("/");
				for (String name : names)
					if (name.equals(id)) {
						correspondingNodeId = node.getId();
						break;
					}
			}
	}

	public String getId() {
		if (correspondingNodeId == null)
			return id;
		else
			return correspondingNodeId;
	}

	public Edge getRefEdge() {
		return edge;
	}

	@Override
	public boolean equals(Object o) {
		if (!(o instanceof Stop))
			return false;

		Stop stop = (Stop) o;
		if (id.equals(stop.id))
			return true;

		return false;
	}

	@Override
	public int hashCode() {
		return id.hashCode();
	}

	@Override
	public String toString() {
		return x + " " + y + " " + edge.getId();
	}

	public void debugPassingRoutes() {
		System.out.println("Stop " + id + " edge id " + edge.getId()
				+ " passing routes at " + MBData.startTime);
		for (TransitRoute route : passingRoutes) {
			int frequency = getRouteFrequency(route, MBData.startTime, 1);
			System.out.println("route " + route.getId() + " with frequency "
					+ frequency);
		}
	}

	public void debugTransitSchedule() {
		// System.out.println(passingRoutes.size()+" routes pass through selected stop "+this.getId()+" they are: ");
		for (int i = 0; i < passingRoutes.size(); i++) {
			List<List<Float>> transitSchedule = getTransitSchedule(passingRoutes
					.get(i));

			// System.out.println(passingRoutes.get(i).getId()
			// +" transitSchedule size "+transitSchedule.size());

			if (transitSchedule.size() == 0)
				continue;

			BusScheduleVisualizer bus = new BusScheduleVisualizer(
					passingRoutes.get(i), transitSchedule);
			bus.render();
		}
	}

	public List<List<Float>> getTransitSchedule(TransitRoute route) {
		List<List<Float>> transitTimes = new ArrayList<List<Float>>();

		Map<Integer, RawBusSchedule> buses = route.getBusSchedule();
		for (Integer busRegNum : buses.keySet()) {
			RawBusSchedule bus = buses.get(busRegNum);
			CalibratedBusSchedule calBus = bus.getCalibratedSchedule();
			List<List<Float>> busTimes = calBus.getTransitSchedule();

			for (List<Float> times : busTimes) {
				transitTimes.add(times);
			}
		}

		return transitTimes;
	}
}
